package com.dynamic.mybatis.web.mvc;

import com.dynamic.mybatis.core.metadata.DynamicMappedStatement;
import com.dynamic.mybatis.core.session.DynamicSqlSessionTemplate;
import com.dynamic.mybatis.core.session.helper.DynamicMappedStatementHelper;
import com.dynamic.mybatis.core.toolkit.BeanUtils;
import com.dynamic.mybatis.core.toolkit.StringUtils;
import com.dynamic.mybatis.web.security.AuthenticationException;
import com.dynamic.mybatis.web.security.SecurityAuthorizationParameter;
import com.dynamic.mybatis.web.security.SecurityParameterHandler;
import com.dynamic.mybatis.web.security.SecurityParameterInterceptHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

@RestController
public class MappedStatementRequestExecuteHandler {

    @Autowired
    private DynamicSqlSessionTemplate sqlSessionTemplate;

    @Autowired
    private SecurityParameterHandler securityParameterHandler;

    public Object execute(@RequestHeader HttpHeaders httpHeaders,@RequestAttribute("org.springframework.web.servlet.HandlerMapping.lookupPath") String url,@RequestParam Map<String,Object> urlParameter, @RequestBody(required = false) Object bodyParameter){
        String contentType = httpHeaders.getFirst(HttpHeaders.CONTENT_TYPE);
        Object parameter = bodyParameter != null && StringUtils.isNotBlank(contentType) && contentType.contains(MediaType.APPLICATION_JSON_VALUE) ? BeanUtils.copy(bodyParameter,urlParameter) : urlParameter;

        String mappedStatementId = url.replaceAll("^/","").replaceAll("/",".");
        //token 处理
        Object param = tokenHandle(httpHeaders,parameter);
        //认证
        Object session = authenticateHandle(mappedStatementId,param);
        if(parameter instanceof Map && session != null){
            ((Map)(parameter)).put("session",session);
        }
        //session处理
        //执行
        Object result =  sqlSessionTemplate.execute(mappedStatementId,parameter);
        //登录处理
        result = loginHandle(mappedStatementId,parameter,result);
        return result;
    }


    private Object tokenHandle(HttpHeaders httpHeaders,Object parameter){
        String token =  httpHeaders.getFirst(HttpHeaders.AUTHORIZATION);
        Object param;
        if(!StringUtils.isNotEmpty(token)){
            param = parameter;
        }else {
            param = new SecurityAuthorizationParameter(token,parameter);
        }
        return param;
    }



    private Object  authenticateHandle(String mappedStatementId,Object param) {
        DynamicMappedStatement dms =  sqlSessionTemplate.getDynamicMappedStatementHelper().getDynamicMappedStatement(mappedStatementId);
        if(dms == null){
            return null;
        }
        if(dms.isSessionContext()|| !dms.isAuth()){
            if((param instanceof SecurityAuthorizationParameter)){
                SecurityAuthorizationParameter parameter = (SecurityAuthorizationParameter) param;
                return securityParameterHandler.getSecurityParameter(dms.getNamespace(),parameter.getToken());
            }
            return null;
        }else {
            //权限不足
            if(!(param instanceof SecurityAuthorizationParameter)){
                throw new AuthenticationException("权限不足");
            }
            //权限不足
            SecurityAuthorizationParameter parameter = (SecurityAuthorizationParameter) param;
            if(StringUtils.isBlank(parameter.getToken())){
                throw new AuthenticationException("权限不足");
            }
            Object session;
            try {
                session = securityParameterHandler.getSecurityParameter(dms.getNamespace(),parameter.getToken());
            }catch (Exception e){
                throw new AuthenticationException("非法token");
            }
            if(session == null){
                throw new AuthenticationException("token失效");
            }
            return session;
        }
    }

    /**
     　* @Description: 该接口为登录接口，使用登录接口的结果调用session类型的接口，并生成token,绑定用户和session并缓存
     　*/
    private Object  loginHandle(String mappedStatementId,Object parameter,Object result){
        DynamicMappedStatementHelper dmsHelper = sqlSessionTemplate.getDynamicMappedStatementHelper();
        DynamicMappedStatement dms =  sqlSessionTemplate.getDynamicMappedStatementHelper().getDynamicMappedStatement(mappedStatementId);
        if(dms == null){
            return result;
        }
        if(dms.isSessionContext()){
            DynamicMappedStatement dmsSession = dmsHelper.mappedStatementValues().stream().filter(DynamicMappedStatement::isSessionContext).findFirst().orElse(null);
            if(dmsSession != null && dmsSession.isEnable()){
                Object sessionContext = sqlSessionTemplate.execute(mappedStatementId,parameter);
                String token = SecurityParameterInterceptHandler.generateToken(BeanUtils.copyGetMap(parameter));
                securityParameterHandler.setSecurityParameter(dmsSession.getNamespace(),token,sessionContext);
                result = token;
            }
        }
        return result;
    }

}
